/* Copyright (c) 2016-2020 Enfry Ltd. All Rights Reserved.
 * 
 * This software is the confidential and proprietary information of Enfry. 
 * You shall not disclose such Confidential Information
 * and shall use it only in accordance with the terms of the agreements
 * you entered into with Enfry.
 */
package com.enfry.storage.service;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;

import com.enfry.storage.BaseService;
import com.enfry.storage.api.IFileOperate;
import com.enfry.storage.common.IMGUtils;
import com.enfry.storage.exception.ExCode;
import com.enfry.storage.exception.StorageException;
import com.jweb.framework.core.Context;

/**
 * 下载文件service
 * 
 * @Title com.enfry.storage.service.FileDownloadService
 * @author liulei
 * @date 2016年7月25日
 */
public class FileDownloadService extends BaseService {

	@Resource
	private IFileOperate fileOperate;
	// 系统临时目录
	private final String tmpDir = System.getProperty("java.io.tmpdir");
	// 原图文件名字匹配
	private final Pattern imgNamePattern = Pattern.compile("((\\w+/){4}[^.]+)(\\.(\\d+))?[^.]*(\\.([^.]+))*");
	private final byte[] defaultDatas;

	public FileDownloadService() throws IOException {
		File tmpFile = new File(Thread.currentThread().getContextClassLoader().getResource("/404.jpg").getPath());
		this.defaultDatas = FileUtils.readFileToByteArray(tmpFile);
	}

	/**
	 * 读取文件API
	 *
	 * @param ctx
	 */
	public void get(Context ctx) {
		try {
			// 附件名attachmentName，有此参数则设为下载响应
			String attachmentName = ctx.getData("attachmentName");
			if (attachmentName != null) {
				HttpServletResponse response = (HttpServletResponse) ctx.getChannelContext().getResponse();
				response.setContentType("application/x-download");
				response.setHeader("Pragma", "No-cache");
				response.setHeader("Cache-Control", "No-cache");
				response.setDateHeader("Expires", 0);
				response.setHeader("Content-Disposition", "attachment; filename=\"" + parse(attachmentName) + "\"");
			}

			String fileCode = ctx.getData("fileCode");
			this.ajaxBytes(ctx, fileOperate.download(fileCode), true);
		} catch (StorageException e) {
			this.ajaxError(ctx, e);
		} catch (Exception e) {
			this.ajaxError(ctx, ExCode.RUNTIME);
		}
	}

	/**
	 * 读取图片API
	 *
	 * @param ctx
	 */
	public void img(Context ctx) {
		try {
			// 附件名attachmentName，有此参数则设为下载响应
			String attachmentName = ctx.getData("attachmentName");
			if (attachmentName != null) {
				HttpServletResponse response = (HttpServletResponse) ctx.getChannelContext().getResponse();
				response.setContentType("application/x-download");
				response.setHeader("Pragma", "No-cache");
				response.setHeader("Cache-Control", "No-cache");
				response.setDateHeader("Expires", 0);
				response.setHeader("Content-Disposition", "attachment;filename=\"" + parse(attachmentName) + "\"");
			}

			// 从fileCode中读取参数值
			String fileCode = ctx.getData("fileCode");
			String[] fileParams = this.getFileParams(fileCode);
			if (fileParams == null) {
				logger.error("不合法的fileCode：" + fileCode);
				this.ajaxError(ctx, ExCode.FILE_CODE_NOT_FOUND);
				return;
			}

			// 文件名，不带参数
			String filename = fileParams[0];
			// 文件后缀名，不带符号"."
			String fileExtName = fileParams[1];
			// 是否加密
			boolean isEncrypted = fileParams[2] == null || "1".equals(fileParams[2]);

			byte[] imgBytes;

			// thumb格式分为两种。整数：代表缩略图百分比，整数x整数：代表缩略图的width和height
			String thumb = ctx.getData("thumb");
			// 参数thumb为空则读取原图
			if (StringUtils.isEmpty(thumb)) {
				imgBytes = fileOperate.download(fileCode);
			} else {
				Map<String, Object> thumbMap = this.getThumb(ctx, fileCode, thumb, filename, fileExtName, isEncrypted);
				imgBytes = (byte[]) thumbMap.get("data");
				isEncrypted = (boolean) thumbMap.get("isEncrypted");
			}

			if (imgBytes == null) {
				logger.warn("找不到图片，fileCode：" + fileCode);
				imgBytes = defaultDatas;
				isEncrypted = false;
			}

			this.ajaxBytes(ctx, imgBytes, isEncrypted);
		} catch (StorageException e) {
			logger.error(e.getMessage(), e);
			this.ajaxError(ctx, e);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			this.ajaxError(ctx, ExCode.RUNTIME);
		}
	}

	/**
	 * 获取缩略图Map
	 *
	 * @param ctx
	 * @param fileCode
	 * @param thumb
	 * @param filename
	 * @param fileExtName
	 * @param isEncrypted
	 * @return Map, isEncrypted：是否已加密，data：字节数据
	 * @throws IOException
	 */
	private Map<String, Object> getThumb(Context ctx, String fileCode, String thumb, String filename, String fileExtName, boolean isEncrypted) throws IOException {
		// 缩略图前缀
		String prefix = isEncrypted ? ".1_" + thumb : ".0_" + thumb;

		Map<String, Object> result = new HashMap<>();

		// 缩略图编码
		String thumbCode = filename + prefix + "." + fileExtName;
		logger.debug("thumbCode: " + thumbCode);
		// 按缩略图编码从服务器下载缩略图文件数据
		byte[] data = fileOperate.download(thumbCode);
		// data不为null，已有缩略图直接输出；data为空则生成缩略图再输出
		if (data == null) {
			// 读取图片
			data = fileOperate.download(fileCode);
			// 解密
			if (isEncrypted)
				data = this.decrypt.getData(data, this.passwd);

			// 新建临时文件
			File tmpFile = new File(tmpDir + UUID.randomUUID());
			FileUtils.writeByteArrayToFile(tmpFile, data);
			// 缩放图片
			IMGUtils.zoom(thumb, tmpFile.getAbsolutePath());
			// 读取缩放后图片的字节数组，未加密
			data = FileUtils.readFileToByteArray(tmpFile);
			// 删除临时文件
			tmpFile.delete();

			// 加密
			byte[] encryptByets = isEncrypted ? this.encrypt.getEncryptBytes(data, this.passwd) : data;
			// 存储缩略图
			String appKey = ctx.getData("appKey");
			fileOperate.uploadSlave(appKey, fileCode, encryptByets, prefix, fileExtName);

			// data是从缩略图片文件读取的未加密数据，修改isEncrypted
			isEncrypted = false;
		}

		result.put("isEncrypted", isEncrypted);
		result.put("data", data);
		return result;
	}

	/**
	 * 分析参数
	 *
	 * @param fileCode group1/M00/00/01/wKgAUFXxQZWACFZyAAvWGL8rcow076.0.jpg
	 * @return ['group1/M00/00/01/wKgAUFXxQZWACFZyAAvWGL8rcow076', 'jpg', '0']
	 */
	private String[] getFileParams(String fileCode) {
		Matcher m = imgNamePattern.matcher(fileCode);
		if (m.matches()) {
			String[] params = new String[3];
			params[0] = m.group(1);
			params[1] = m.group(6);
			params[2] = m.group(4);
			return params;
		}
		return null;
	}

	private static String parse(String sIn) {
		if (sIn == null || sIn.equals(""))
			return sIn;
		try {
			return new String(sIn.getBytes("UTF-8"), "ISO-8859-1");
		} catch (UnsupportedEncodingException usex) {
			return sIn;
		}
	}
}
